﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Xml;
using GeoAPI.Geometries;
using YJKGridTopologyCal.Utilities;

namespace YJKGridTopologyCal.IO.GML2
{
	public class GMLWriter
	{
		protected static NumberFormatInfo NumberFormatter
		{
			get
			{
				return Global.GetNfi();
			}
		}

		public XmlReader Write(IGeometry geometry)
		{
			byte[] bytes = this.GetBytes(geometry);
			using (Stream stream = new MemoryStream(bytes))
			{
				this.Write(geometry, stream);
			}
			return new XmlTextReader(new MemoryStream(bytes));
		}

		public void Write(IGeometry geometry, Stream stream)
		{
			XmlTextWriter xmlTextWriter = new XmlTextWriter(stream, null)
			{
				Namespaces = true
			};
			this.Write(geometry, xmlTextWriter);
			((IDisposable)xmlTextWriter).Dispose();
		}

		protected void Write(Coordinate coordinate, XmlTextWriter writer)
		{
			writer.WriteStartElement("gml", "coord", "http://www.opengis.net/gml");
			writer.WriteElementString("gml", "X", "http://www.opengis.net/gml", coordinate.X.ToString("g", GMLWriter.NumberFormatter));
			writer.WriteElementString("gml", "Y", "http://www.opengis.net/gml", coordinate.Y.ToString("g", GMLWriter.NumberFormatter));
			writer.WriteEndElement();
		}

		protected void Write(Coordinate[] coordinates, XmlTextWriter writer)
		{
			foreach (Coordinate coordinate in coordinates)
			{
				this.Write(coordinate, writer);
			}
		}

		protected void WriteCoordinates(Coordinate[] coordinates, XmlTextWriter writer)
		{
			writer.WriteStartElement("gml", "coordinates", "http://www.opengis.net/gml");
			List<string> list = new List<string>(coordinates.Length);
			foreach (Coordinate coordinate in coordinates)
			{
				list.Add(string.Format(GMLWriter.NumberFormatter, "{0},{1}", new object[]
				{
					coordinate.X,
					coordinate.Y
				}));
			}
			writer.WriteString(string.Join(" ", list.ToArray()));
			writer.WriteEndElement();
		}

		public void Write(IGeometry geometry, XmlTextWriter writer)
		{
			if (geometry is IPoint)
			{
				this.Write(geometry as IPoint, writer);
				return;
			}
			if (geometry is ILineString)
			{
				this.Write(geometry as ILineString, writer);
				return;
			}
			if (geometry is IPolygon)
			{
				this.Write(geometry as IPolygon, writer);
				return;
			}
			if (geometry is IMultiPoint)
			{
				this.Write(geometry as IMultiPoint, writer);
				return;
			}
			if (geometry is IMultiLineString)
			{
				this.Write(geometry as IMultiLineString, writer);
				return;
			}
			if (geometry is IMultiPolygon)
			{
				this.Write(geometry as IMultiPolygon, writer);
				return;
			}
			if (geometry is IGeometryCollection)
			{
				this.Write(geometry as IGeometryCollection, writer);
				return;
			}
			throw new ArgumentException("Geometry not recognized: " + geometry);
		}

		protected void Write(IPoint point, XmlTextWriter writer)
		{
			writer.WriteStartElement("gml", "Point", "http://www.opengis.net/gml");
			this.Write(point.Coordinate, writer);
			writer.WriteEndElement();
		}

		protected void Write(ILineString lineString, XmlTextWriter writer)
		{
			writer.WriteStartElement("gml", "LineString", "http://www.opengis.net/gml");
			this.WriteCoordinates(lineString.Coordinates, writer);
			writer.WriteEndElement();
		}

		protected void Write(ILinearRing linearRing, XmlTextWriter writer)
		{
			writer.WriteStartElement("gml", "LinearRing", "http://www.opengis.net/gml");
			this.WriteCoordinates(linearRing.Coordinates, writer);
			writer.WriteEndElement();
		}

		protected void Write(IPolygon polygon, XmlTextWriter writer)
		{
			writer.WriteStartElement("gml", "Polygon", "http://www.opengis.net/gml");
			writer.WriteStartElement("outerBoundaryIs", "http://www.opengis.net/gml");
			this.Write(polygon.ExteriorRing as ILinearRing, writer);
			writer.WriteEndElement();
			for (int i = 0; i < polygon.NumInteriorRings; i++)
			{
				writer.WriteStartElement("innerBoundaryIs", "http://www.opengis.net/gml");
				this.Write(polygon.InteriorRings[i] as ILinearRing, writer);
				writer.WriteEndElement();
			}
			writer.WriteEndElement();
		}

		protected void Write(IMultiPoint multiPoint, XmlTextWriter writer)
		{
			writer.WriteStartElement("gml", "MultiPoint", "http://www.opengis.net/gml");
			for (int i = 0; i < multiPoint.NumGeometries; i++)
			{
				writer.WriteStartElement("pointMember", "http://www.opengis.net/gml");
				this.Write(multiPoint.Geometries[i] as IPoint, writer);
				writer.WriteEndElement();
			}
			writer.WriteEndElement();
		}

		protected void Write(IMultiLineString multiLineString, XmlTextWriter writer)
		{
			writer.WriteStartElement("gml", "MultiLineString", "http://www.opengis.net/gml");
			for (int i = 0; i < multiLineString.NumGeometries; i++)
			{
				writer.WriteStartElement("lineStringMember", "http://www.opengis.net/gml");
				this.Write(multiLineString.Geometries[i] as ILineString, writer);
				writer.WriteEndElement();
			}
			writer.WriteEndElement();
		}

		protected void Write(IMultiPolygon multiPolygon, XmlTextWriter writer)
		{
			writer.WriteStartElement("gml", "MultiPolygon", "http://www.opengis.net/gml");
			for (int i = 0; i < multiPolygon.NumGeometries; i++)
			{
				writer.WriteStartElement("polygonMember", "http://www.opengis.net/gml");
				this.Write(multiPolygon.Geometries[i] as IPolygon, writer);
				writer.WriteEndElement();
			}
			writer.WriteEndElement();
		}

		protected void Write(IGeometryCollection geometryCollection, XmlTextWriter writer)
		{
			writer.WriteStartElement("gml", "MultiGeometry", "http://www.opengis.net/gml");
			for (int i = 0; i < geometryCollection.NumGeometries; i++)
			{
				writer.WriteStartElement("geometryMember", "http://www.opengis.net/gml");
				this.Write(geometryCollection.Geometries[i], writer);
				writer.WriteEndElement();
			}
			writer.WriteEndElement();
		}

		protected byte[] GetBytes(IGeometry geometry)
		{
			if (geometry is IPoint)
			{
				return new byte[this.SetByteStreamLength(geometry as IPoint)];
			}
			if (geometry is ILineString)
			{
				return new byte[this.SetByteStreamLength(geometry as ILineString)];
			}
			if (geometry is IPolygon)
			{
				return new byte[this.SetByteStreamLength(geometry as IPolygon)];
			}
			if (geometry is IMultiPoint)
			{
				return new byte[this.SetByteStreamLength(geometry as IMultiPoint)];
			}
			if (geometry is IMultiLineString)
			{
				return new byte[this.SetByteStreamLength(geometry as IMultiLineString)];
			}
			if (geometry is IMultiPolygon)
			{
				return new byte[this.SetByteStreamLength(geometry as IMultiPolygon)];
			}
			if (geometry is IGeometryCollection)
			{
				return new byte[this.SetByteStreamLength(geometry as IGeometryCollection)];
			}
			throw new ArgumentException("ShouldNeverReachHere");
		}

		protected int SetByteStreamLength(IGeometry geometry)
		{
			if (geometry is IPoint)
			{
				return this.SetByteStreamLength(geometry as IPoint);
			}
			if (geometry is ILineString)
			{
				return this.SetByteStreamLength(geometry as ILineString);
			}
			if (geometry is IPolygon)
			{
				return this.SetByteStreamLength(geometry as IPolygon);
			}
			if (geometry is IMultiPoint)
			{
				return this.SetByteStreamLength(geometry as IMultiPoint);
			}
			if (geometry is IMultiLineString)
			{
				return this.SetByteStreamLength(geometry as IMultiLineString);
			}
			if (geometry is IMultiPolygon)
			{
				return this.SetByteStreamLength(geometry as IMultiPolygon);
			}
			if (geometry is IGeometryCollection)
			{
				return this.SetByteStreamLength(geometry as IGeometryCollection);
			}
			throw new ArgumentException("ShouldNeverReachHere");
		}

		protected int SetByteStreamLength(IGeometryCollection geometryCollection)
		{
			int num = 150;
			foreach (IGeometry byteStreamLength in geometryCollection.Geometries)
			{
				num += this.SetByteStreamLength(byteStreamLength);
			}
			return num;
		}

		protected int SetByteStreamLength(IMultiPolygon multiPolygon)
		{
			int num = 150;
			foreach (IPolygon byteStreamLength in multiPolygon.Geometries)
			{
				num += this.SetByteStreamLength(byteStreamLength);
			}
			return num;
		}

		protected int SetByteStreamLength(IMultiLineString multiLineString)
		{
			int num = 150;
			foreach (ILineString byteStreamLength in multiLineString.Geometries)
			{
				num += this.SetByteStreamLength(byteStreamLength);
			}
			return num;
		}

		protected int SetByteStreamLength(IMultiPoint multiPoint)
		{
			int num = 150;
			foreach (IPoint byteStreamLength in multiPoint.Geometries)
			{
				num += this.SetByteStreamLength(byteStreamLength);
			}
			return num;
		}

		protected int SetByteStreamLength(IPolygon polygon)
		{
			return 150 + polygon.NumPoints * 200;
		}

		protected int SetByteStreamLength(ILineString lineString)
		{
			return 150 + lineString.NumPoints * 200;
		}

		protected int SetByteStreamLength(IPoint point)
		{
			return 350;
		}

		private const int InitValue = 150;

		private const int CoordSize = 200;
	}
}
